package com.lewis.core.utils.file;

import javazoom.spi.mpeg.sampled.file.MpegAudioFileReader;
import ws.schild.jave.*;

import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;

/**
 * MP3转PCM
 *
 * @author Lewis
 */
public class AudioUtil {

	private static AudioUtil audioUtil = null;

	private AudioUtil() {
	}

	//双判断，解决单利问题
	public static AudioUtil getInstance() {
		if (audioUtil == null) {
			synchronized (AudioUtil.class) {
				if (audioUtil == null) {
					audioUtil = new AudioUtil();
				}
			}
		}
		return audioUtil;
	}

	/**
	 * MP3文件转换PCM文件
	 *
	 * @param mp3filepath 原始文件路径
	 * @param pcmfilepath 转换文件的保存路径
	 * @return
	 * @throws Exception
	 */
	public boolean convertMp32Pcm(String mp3filepath, String pcmfilepath) {
		try {
			//获取文件的音频流，pcm的格式
			AudioInputStream audioInputStream = getPcmAudioInputStream(mp3filepath);
			//将音频转化为  pcm的格式保存下来
			AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, new File(pcmfilepath));
			return true;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 播放MP3文件
	 *
	 * @param mp3filepath 文件路径
	 * @throws Exception
	 */
	public void playMp3(String mp3filepath) throws Exception {
		//获取音频为pcm的格式
		AudioInputStream audioInputStream = getPcmAudioInputStream(mp3filepath);

		// 播放
		if (audioInputStream == null) {
			System.out.println("null audiostream");
			return;
		}
		//获取音频的格式
		AudioFormat targetFormat = audioInputStream.getFormat();
		DataLine.Info dinfo = new DataLine.Info(SourceDataLine.class, targetFormat, AudioSystem.NOT_SPECIFIED);
		//输出设备
		SourceDataLine line = null;
		try {
			line = (SourceDataLine) AudioSystem.getLine(dinfo);
			line.open(targetFormat);
			line.start();

			int len = -1;
//            byte[] buffer = new byte[8192];
			byte[] buffer = new byte[1024];
			//读取音频文件
			while ((len = audioInputStream.read(buffer)) > 0) {
				//输出音频文件
				line.write(buffer, 0, len);
			}

			// Block等待临时数据被输出为空
			line.drain();

			//关闭读取流
			audioInputStream.close();

			//停止播放
			line.stop();
			line.close();

		} catch (Exception ex) {
			ex.printStackTrace();
			System.out.println("audio problem " + ex);

		}
	}

	/**
	 * 获取文件的音频流
	 *
	 * @param mp3filepath mp3文件路径
	 * @return AudioInputStream
	 */
	private AudioInputStream getPcmAudioInputStream(String mp3filepath) {
		File mp3 = new File(mp3filepath);
		AudioInputStream audioInputStream = null;
		AudioFormat targetFormat = null;
		try {
			AudioInputStream in = null;

			//读取音频文件的类
			MpegAudioFileReader mp = new MpegAudioFileReader();
			in = mp.getAudioInputStream(mp3);
			AudioFormat baseFormat = in.getFormat();

			//设定输出格式为pcm格式的音频文件
			targetFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(), 16,
					baseFormat.getChannels(), baseFormat.getChannels() * 2, baseFormat.getSampleRate(), false);

			//输出到音频
			audioInputStream = AudioSystem.getAudioInputStream(targetFormat, in);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return audioInputStream;
	}

	/**
	 * 导入依赖
	 * <dependency>
	 * <groupId>ws.schild</groupId>
	 * <artifactId>jave-all-deps</artifactId>
	 * <version>2.6.0</version>
	 * </dependency>
	 */
	// 程序员是不需要格式工厂的，直接自己写代码解决。
	// 算法如果我们写不来，我们可以做调包侠呀。
	// 技术都是站在巨人的肩膀上，我调包我快乐！没必要抵触。
	// 以MP3转为amr格式举例：
	public static void main(String[] args) {
		// String sourcePath = "D:\\Document\\CloudMusic\\Music\\灰澈 - 星茶会.mp3";
		// String targetPath = "D:\\Document\\CloudMusic\\Music\\灰澈 - 星茶会.amr";
		// System.out.println(mp32amr(sourcePath, targetPath));
		// encodingFormats();
		codec();
	}

	/**
	 * 将支持的音频格式转成amr
	 * @param sourcePath 资源路径
	 * @param targetPath 目标路径
	 * @return
	 */
	public static boolean audio2amr(String sourcePath, String targetPath) {
		boolean succeeded = true;
		try {
			// 获取两个文件对象
			File source = new File(sourcePath);
			File target = new File(targetPath);

			// 配置生成的音频参数
			AudioAttributes audio = new AudioAttributes();
			// audio.setCodec("pcm_s16le");// wav
			// audio.setCodec("libmp3lame");// mp3
			audio.setCodec("libvo_amrwbenc");// amr
			audio.setBitRate(16000);
			audio.setChannels(1);
			audio.setSamplingRate(16000);

			// 配置编码参数
			EncodingAttributes attrs = new EncodingAttributes();
			attrs.setFormat("amr");
			attrs.setAudioAttributes(audio);

			// Encode
			Encoder encoder = new Encoder();
			encoder.encode(new MultimediaObject(source), target, attrs);

		} catch (Exception ex) {
			ex.printStackTrace();
			succeeded = false;
		}
		return succeeded;
	}

	// 对于格式属性，可以调整成需要的数值。如果需要其他的Codec，可以使用如下方法打印出所有支持的Codec，选择所需要的。
	public static void codec() {
		Encoder encoder = new Encoder();
		try {
			for (int i = 0; i < encoder.getAudioEncoders().length; i++) {
				System.out.println(encoder.getAudioEncoders()[i].toString());
			}
		} catch (EncoderException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	// 对于支持的格式种类，可以使用如下方法打印出所有支持的格式。
	public static void encodingFormats() {
		Encoder encoder = new Encoder();
		try {
			for (int i = 0; i < encoder.getSupportedEncodingFormats().length; i++) {
				System.out.println(encoder.getSupportedEncodingFormats()[i].toString());
			}
		} catch (EncoderException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}